<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @example 三种情况
 *
 */

class Model_Attachment extends Model_Database {
	const UPLOAD_ERR_MAXSIZE = 100;
	const UPLOAD_ERR_EXT = 101;
	const DOWNLOAD_ERR_URL = 104;
	const DOWNLOAD_ERR_FILE = 105;
	private $_config = array();
	public function __construct()
	{
		parent::__construct();

		$this->_config = Kohana::$config->load('attachment');
		//$_columns = $this->_db->list_columns('attachment','ext');
		//$this->config['ext'] = array_get_recursive($_columns,'ext/options');

	}

	public function upload( $uid, $field_name, $description = '')
	{

		if (!isset($_FILES[$field_name]) || !is_uploaded_file($_FILES[$field_name]["tmp_name"]) || $_FILES[$field_name]["error"] != 0) {
			return $_FILES[$field_name]['error'];
		}

		ignore_user_abort(TRUE);
		set_time_limit(0);

		//$ext = strtolower(pathinfo($_FILES[$field_name]['name'],PATHINFO_EXTENSION));

		return $this->save($uid, $_FILES[$field_name]["tmp_name"], $_FILES[$field_name]['name'], NULL , NULL, $description  );
	}

	public function download($uid, $url, $filename = NULL, $ext = NULL)
	{

		if (empty($url))
			return Model_Attachment::DOWNLOAD_ERR_URL;

		ignore_user_abort(TRUE);
		set_time_limit(0);

		$file_path = tempnam('','');
		$fp = fopen($file_path,'wb+');

		$request = Request::factory($url)->client(Request_Client_External::factory(array(),'Request_Client_Curl')->options(CURLOPT_FILE,$fp)->options(CURLOPT_BINARYTRANSFER,TRUE))->method('GET');

		$response = $request->execute();

		fclose($fp);

		if ($response->status() != '200')
			return Model_Attachment::DOWNLOAD_ERR_FILE;

		$download_filename = $response->headers('Content-Disposition');

		$basename = mb_basename($url);//pathinfo($url,PATHINFO_BASENAME);
		if (!empty($download_filename))
		{
			preg_match('/filename\s*=\s*(\S*)/i',  $download_filename, $tmp);
			!empty($tmp) && $basename = mb_basename(trim($tmp[1],'\'"'));//pathinfo($download_filename,PATHINFO_BASENAME);
		}

		return $this->save($uid, $file_path, $basename, $filename, $ext, 'Download from:' . $url);

	}


	public function save($uid, $src_file_path, $old_basename ,$file_name = NULL, $file_ext = NULL , $description = NULL)
	{
		if (!file_exists($src_file_path))
			return FALSE;

		is_null($file_ext) && $file_ext = strtolower(pathinfo($old_basename,PATHINFO_EXTENSION));
		is_null($file_name) && $file_name = mb_basename($old_basename, '.'.$file_ext); //支持中文的basename

		$size = filesize($src_file_path);

		if(!in_array($file_ext, $this->_config['ext']))
			return Model_Attachment::UPLOAD_ERR_EXT;
		if ($size > $this->_config['maxsize'])
			return Model_Attachment::UPLOAD_ERR_MAXSIZE;

		//传文件都耗费了那么多时间,还怕md5?
		$hash = md5_file($src_file_path);

		$file = $this->get_file_byhash($hash, $size);

		$afid = 0;

		if (empty($file))
		{

			while ( file_exists( $newpath = $this->get_real_path( $new_basename = $this->get_hash_basename() ) ) );
			$newrpath = $this->get_relative_path($new_basename);
			$dir = dirname($newpath);
			!is_dir($dir) && mkdir($dir,0777,true);

			if(is_uploaded_file($src_file_path))
				move_uploaded_file($src_file_path,$newpath);
			else
			{
				if (!rename($src_file_path,$newpath))
				{
					@copy($src_file_path,$newpath);
					@unlink($src_file_path);
				}
			}
			@chmod($newpath, 0777);
			
			$t = DB::insert('attachment_files',array('timeline','basename','path','hash','size'))->values(array(time(), $new_basename, $newrpath, $hash, $size))->execute();
			$afid = array_shift($t);
		}
		else
		{
			$afid = $file['afid'];
			@unlink($src_file_path);
		}

		$query = DB::insert('attachment',array('afid','filename','ext','src_basename','description','uid','timeline'))->values(array($afid, $file_name, $file_ext,$old_basename, $description, $uid, time()));
		$t = $query->execute();
		$aid = array_shift($t);

		return $this->get($aid);
	}

	public function get_file_byhash($hash,$size)
	{
		$result = array();
		$hashkey = 'files_'.$hash.'_'.$size;
		if (is_null($result = $this->get_cache($hashkey)))
		{
			$query = DB::select('*')->from('attachment_files')->where('hash','=',$hash)->and_where('size','=',$size);
			$result = $query->execute()->current();
			$this->set_cache($hashkey,$result);
		}
		return $result;
	}

	public function get_file($afid)
	{
		$result = array();
		$hashkey = 'files_'.$afid;
		if (is_null($result = $this->get_cache($hashkey)))
		{
			$query = DB::select('*')->from('attachment_files')->where('afid','=',$afid);
			$result = $query->execute()->current();
			$this->set_cache($hashkey,$result);
		}
		return $result;
	}

	public function get($aid)
	{
		$result = array();
		$hashkey = $aid;
		if (is_null($result = $this->get_cache($hashkey)))
		{
			$query = DB::select('a.*',array('a.src_basename','original_basename'),'b.path','b.size','b.hash','b.basename')->from(array('attachment','a'))->join(array('attachment_files','b'))->on('a.afid','=','b.afid')->where('a.aid','=',$aid);
			$result = $query->execute()->current();
			
			if (!empty($result))
			{
				$result['displayname'] = $result['filename'].(!empty($result['ext']) ?  '.'.$result['ext'] : '' );
			}
			$this->set_cache($hashkey,$result);
		}
		return $result;
	}

	public function get_type($ext)
	{
		$ext = strtolower($ext);
		foreach ($this->_config['file_type'] as $key => $value)
		{
			if (in_array($ext, $value))
				return $key;
		}
		return NULL;
	}

	public function search($fields, $order_by = array('a.timeline' => 'DESC'), $page = 1, $pagesize = 0)
	{
		$_fields = array('aid' => array(), 'afid' => array(), 'filename' => '', 'duplicate' => NULL, 'ext' => array(), 'uid' => array(), 'timeline' => array('min' => NULL, 'max' => NULL, ), 'size' => array('min' => NULL, 'max' => NULL, ));
		$fields = to_array_selector($fields, 'aid,afid,ext,uid');
		$fields = _extends($fields, $_fields);

	
		$query = DB::select()->from(array('attachment','a'))->join(array('attachment_files','b'), 'INNER')->on('a.afid','=','b.afid');
		$fields['duplicate'] && $query->group_by('a.afid');
		!empty($fields['aid']) && $query->and_where('a.aid','IN',$fields['aid']);
		!empty($fields['afid']) && $query->and_where('a.afid','IN',$fields['afid']);
		!empty($fields['filename']) && $query->and_where('a.filename','LIKE','%'.$fields['filename'].'%');
		!empty($fields['ext']) && $query->and_where('a.ext','IN',$fields['ext']);
		!empty($fields['hash']) && $query->and_where('b.hash','=',$fields['ext']);
		!empty($fields['uid']) && $query->and_where('a.uid','IN',$fields['uid']);
		!is_null($fields['size']['min']) && $query->and_where('b.size','>=',$fields['size']['min']);
		!is_null($fields['size']['max']) && $query->and_where('b.size','<=',$fields['size']['min']);
		!is_null($fields['timeline']['min']) && $query->and_where('a.timeline','>=',$fields['timeline']['min']);
		!is_null($fields['timeline']['max']) && $query->and_where('a.timeline','<=',$fields['timeline']['max'] + 86400);
		foreach ($order_by as $key => $value)
			$query->order_by($key, $value);

		$result = $this->make_page($query, array('a.*',array('a.src_basename','original_basename'),'b.path','b.size','b.hash','b.basename'), 'a.aid', 'aid', $page, $pagesize);
		return $result;
	}

	public function get_symlink($aid)
	{
		$data = $this->get($aid);
		if (empty($data))
			return FALSE;

		$path = Kohana::$cache_dir.DIRECTORY_SEPARATOR.'attachment,'.md5($aid).'.'.$data['ext'];
		!file_exists($path) && @symlink($this->get_real_rpath($data['path']), $path);
		return $path;
	}

	public function get_symlink_url($aid, $protocol = NULL)
	{
		$path = $this->get_symlink($aid);
		if (empty($path))
			return FALSE;

		return URL::site(str_replace(APPPATH, '', $path), $protocol, FALSE);
	}

	public function unlink_symlink($aid)
	{
		$data = $this->get($aid);
		if (empty($data))
			return FALSE;
		$path = Kohana::$cache_dir.DIRECTORY_SEPARATOR.'attachment,'.md5($aid).'.'.$data['ext'];
		@unlink($path);
	}

	public function get_real_rpath($relative_path)
	{
		return APPPATH.$relative_path;
	}

	private function get_real_path($basename)
	{
		return APPPATH.$this->get_relative_path($basename);
	}

	private function get_relative_path($basename)
	{
		return $this->get_hash_path($basename);
	}

	public function get_url($aid, $protocol = NULL, $filename = NULL)
	{
		return  URL::site(!empty($filename) ? 'attachment/index/'.$aid.'/'.urlencode($filename) : 'attachment?aid='.$aid, $protocol, FALSE);
	}

	private function get_hash_path($basename)
	{
		$md5 = md5($basename . md5($basename));
		return $this->_config['path'].$md5[0].$md5[1].'/'.$md5[2].$md5[3].'/'.$md5[4].$md5[5].','.$basename;
	}

	private function get_hash_basename()
	{
		return uniqid(date('YmdHis,') . rand(100000,999999) . ',')  . (!empty($this->_config['normal_ext']) ? '.' . $this->_config['normal_ext'] : '');
	}

}